import typing
from django.db.models import QuerySet, Count, Avg
from marshmallow.orderedset import OrderedSet

from firstDjango.exceptions import FormException
from index.models import Book
from index.models import PubName
from index.models import Author


# 添加书
def add_book(book_dict):
    book = Book(**book_dict)
    book.save()
    return book


# 删除书信息
def delete_book(book_id):
    data = Book.objects.filter(id=book_id)
    if not data:
        raise FormException("书籍不存在")
    data.delete()


# 修改书信息
def update_book_info(book_dict):
    book_id = book_dict.pop("id")
    count =  Book.objects.filter(id=book_id).update(**book_dict)
    if count > 0:
        return Book.objects.get(id=book_id)
    raise FormException("书籍不存在")


# 判断书是否存在
def judge_book(number):
    data = Book.objects.filter(number=number)
    # 多对多关系查找
    # authors_obj = book_obj.authors.all().values("id")
    # authors_exist = list(authors_obj)[0]['id']
    if data:
        book_id = list(data)[0].id
        return book_id
    else:
        return False


# 通过书编号查询书信息
def getBook_by_number(number):
    data = Book.objects.filter(number=number)
    if data:
        return getBook(data)
    else:
        return False


# 通过书名查询书信息
def getBook_by_title(book_title):
    data = Book.objects.filter(title=book_title)
    if data:
        return getBook(data)
    else:
        return False


# 获取书信息
def getBook(data):
    book = data[0]
    authors = book.authors.all().values("name")
    book_authors = []
    for i in range(len(authors)):
        book_authors.append(authors[i]["name"])
    pub_data = PubName.objects.filter(id=book.pub_id)
    pubName = pub_data[0].pubname
    book_info = {
        "book_id": book.id,
        "number": book.number,
        "title": book.title,
        "price": book.price,
        "retail_price": book.retail_price,
        "pub": pubName,
        "authors": book_authors
    }
    return book_info


# 添加出版社
def add_pub(pubname):
    pub = PubName(pubname=pubname)
    pub.save()
    return pub.id


# 删除出版社
def delete_pub(pub_id):
    pub = PubName.objects.filter(id=pub_id)
    pub.delete()
    pub_flag = PubName.objects.filter(id=pub_id)
    if pub_flag:
        return False
    else:
        return True


# 判断出版社是否存在
def get_or_create_pub(pubname):
    try:
        pub = PubName.objects.get(pubname=pubname)
    except PubName.DoesNotExist:
        pub = PubName(pubname=pubname)
        pub.save()
    return pub.id


# 添加作者
def add_author(number, name, company, email):
    author = Author(number=number, name=name, company=company, email=email)
    author.save()
    return author.id


# 删除作者
def delete_author(author_id):
    author = Author.objects.filter(id=author_id)
    if author:
        author.delete()
        author_flag = Author.objects.filter(id=author_id)
        if author_flag:
            msg = "删除失败"
        else:
            msg = "删除成功"
        return msg
    else:
        return False


# 修改作者信息
def update_author(author_id, number, name, company, email):
    flag = Author.objects.filter(id=author_id).update(name=name, company=company, email=email)
    if flag:
        return True
    else:
        return False


# 通过id查询作者
def getAuthor_by_id(author_id):
    data = Author.objects.filter(id=author_id)
    if data:
        return author_model2dict(data)
    else:
        return False


# 通过作者编号查询作者信息
def getAuthor_by_number(number):
    data = Author.objects.filter(number=number)
    if data:
        return author_model2dict(data)
    else:
        return False


# 通过作者名字名查询作者信息
def getAuthor_by_name(author_name):
    data = Author.objects.filter(name=author_name)
    if data:
        return author_model2dict(data)
    else:
        return False


def get_authors_by_names(author_names):
    if not isinstance(author_names, list):
        author_names = {author_names.strip()}
    else:
        author_names = OrderedSet([a.strip() for a in author_names])

    authors = Author.objects.filter(name__in=author_names)
    exist_author_names = {author.name for author in authors}
    new_author_name = author_names - exist_author_names
    new_authors = [Author(name=name) for name in new_author_name]
    for author in new_authors:
        author.save()
    return list(authors) + new_authors

# 获得作者信息
def author_model2dict(data):
    author = data[0]
    author_info = {
        "author_id": author.id,
        "number": author.number,
        "name": author.name,
        "company": author.company,
        "email": author.email
    }
    return author_info


# 判断作者是否存在
def judge_authors(number):
    data = Author.objects.filter(number=number)
    if data:
        author_list = data[0]
        return author_list.id
    else:
        return False


def fetch_books(offset, limit, order_by: str=None, desc=True, filter_dict=None) -> typing.Tuple[int, QuerySet[Book]]:
    books = Book.objects.select_related("pub").prefetch_related("authors")\
        .annotate(Avg("bookcomment__score")).annotate(Count("bookcomment__id"))

    if order_by == "rate":
        order_by = "bookcomment__score__avg"
    elif order_by == "comment_count":
        order_by = "bookcomment__id__count"

    if order_by:
        if desc:
            order_by = "-" + order_by
        books = books.order_by(order_by)

    if filter_dict:
        books = books.filter(**filter_dict)
    total_count = books.count()

    return total_count, books[offset:offset + limit]
